//
//  NetCacheData.m
//  why
//
//  Created by lzy on 16/1/27.
//  Copyright © 2016年 刘赞黄Telen. All rights reserved.
//

#import "NetCacheData.h"
#import "ConstDefine.h"

@interface Cacheinfo : NSObject
@property (nonatomic, strong) NSData *saveData;
@property (nonatomic, strong) NSDate *saveTime;
@end

@implementation Cacheinfo

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:[self saveData] forKey:NSStringFromSelector(@selector(saveData))];
    [aCoder encodeObject:[self saveTime] forKey:NSStringFromSelector(@selector(saveTime))];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        self.saveData = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(saveData))];
        self.saveTime = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(saveTime))];
    }
    return self;
}
@end

@implementation NSData (CacheDate)
ASSOCIATED(cacheDate, setCacheDate, NSDate*, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
@end;

@implementation NSDictionary (CacheDateDic)
ASSOCIATED(cacheDate, setCacheDate, NSDate*, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
@end

@implementation NSArray (CacheDateArr)
ASSOCIATED(cacheDate, setCacheDate, NSDate*, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
@end

#pragma mark NetCacheData

#define NetCachePath    @"NetCacheData2"

@implementation NetCacheData
{
    NSString* filePath;
}

static NetCacheData* singleNetCacheDatat = nil;

+ (NetCacheData *)shareSingle
{
    if (!singleNetCacheDatat) {
        singleNetCacheDatat = [[NetCacheData alloc] init];
    }
    return singleNetCacheDatat;
}

- (NSString*)getCahcePath
{
    if (filePath == nil) {
        NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask,YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        filePath = documentsDirectory;
    }
    return filePath;
}

- (NSString *)getFileNameWithPort:(NSString*)port BaseUrl:(NSString*)baseUrl KeyId:(NSString *)keyId {
    //hash文件名
    NSMutableString *hashUrl = [NSMutableString stringWithString:@""];
    if (!baseUrl || [baseUrl isEqualToString:@""]) {
        baseUrl = @"";
    }
    [hashUrl appendFormat:@"%@",baseUrl];
    [hashUrl appendString:@"_"];
    
    if (!port || [port isEqualToString:@""]) {
        port = @"";
    }
    [hashUrl appendFormat:@"%@",port];
    [hashUrl appendString:@"_"];
    
    if (!keyId || [keyId isEqualToString:@""]) {
        keyId = @"";
    }
    [hashUrl appendFormat:@"%@",keyId];
    [hashUrl appendString:@"_"];
    
    NSString *hashName = [NSString stringWithFormat:@"%lld",(unsigned long long)[hashUrl hash]];
    return hashName;
}

- (void)keepCachPath:(NSString*)cachePath
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL ret = [fileManager fileExistsAtPath:cachePath];
    if (!ret) {
        [fileManager createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:NULL];
    }
}

- (NSString *)enterTheFilePath {
    NSString *documentsDirectory = [self getCahcePath];
    NSString *cachePath = [documentsDirectory stringByAppendingPathComponent:NetCachePath];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self keepCachPath:cachePath];
    });
    return cachePath;
}


#pragma mark - For NSArray

- (void)adNetCacheDataWithPort:(NSString *)port
                       baseUrl:(NSString *)baseUrl
                         keyID:(NSString *)keyid
              andResponseArray:(NSArray *)retArr
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:retArr];
        if (retArr.cacheDate) {
            data.cacheDate = retArr.cacheDate;
        }else{
            data.cacheDate = [NSDate date];
        }
        [self addNetCacheDataWithPort:port baseUrl:baseUrl keyID:keyid andResponseData:data];
    });
}

- (void)getNetCacheDataWithPort:(NSString *)port
                             baseUrl:(NSString *)baseUrl
                               keyID:(NSString *)keyid
                      completed:(void (^)(NSArray *))comp
{
    [self getNetCaCheDataWithPort:port baseUrl:baseUrl keyID:keyid completed:^(NSData *responseData) {
        if (responseData) {
            NSArray *retArr = [NSKeyedUnarchiver unarchiveObjectWithData:responseData];
            retArr.cacheDate = responseData.cacheDate;
            if(comp)comp(retArr);
        }else {
           if(comp)comp(nil);
        }
    }];
}

#pragma mark - For NSDictionary

- (void)addNetCacheDataWithPort:(NSString *)port
                        baseUrl:(NSString *)baseUrl
                          keyID:(NSString *)keyid
                 andResponseDic:(NSDictionary *)retDic
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        NSData* data = [NSKeyedArchiver archivedDataWithRootObject:retDic];
        if (retDic.cacheDate) {
            data.cacheDate = retDic.cacheDate;
        }else{
            data.cacheDate = [NSDate date];
        }
        [self addNetCacheDataWithPort:port baseUrl:baseUrl keyID:keyid andResponseData:data];
    });
}


- (void)getNetChacheDataWithPort:(NSString *)port
                                   baseUrl:(NSString*)baseUrl
                                     keyID:(NSString *)keyid
                                 completed:(void (^)(NSDictionary *))comp
{
    [self getNetCaCheDataWithPort:port baseUrl:baseUrl keyID:keyid completed:^(NSData *responseData) {
        NSDictionary *retDic = nil;
        @try {
            if (responseData) {
               retDic = [NSKeyedUnarchiver unarchiveObjectWithData:responseData];
            }
        } @catch (NSException *exception) {
            NSLog(@"NetCacheData[port:%@ keyid:%@]--> %@",port,keyid,exception);
        } @finally {
            
        }
        retDic.cacheDate = responseData.cacheDate;
        if(comp)comp(retDic);
    }];
}

#pragma mark - For NSObject
- (void)addNetChacheModelWithPort:(NSString *)port
                          baseUrl:(NSString *)baseUrl
                            keyID:(NSString *)keyid
                            model:(id)model
                        completed:(void (^)(BOOL))comp
{
    if(comp)dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        BOOL ret = NO;
        if (model) {
            NSString *hashName = [self getFileNameWithPort:port BaseUrl:baseUrl KeyId:keyid];
            NSString *documentsDirectory = [self enterTheFilePath];
            NSString *finalFileName = [documentsDirectory stringByAppendingPathComponent:hashName];
            ret  = [NSKeyedArchiver archiveRootObject:model toFile:finalFileName];
        }
        comp(ret);
    });
}

- (void)getNetCaCheModelWithPort:(NSString *)port
                       baseUrl:(NSString *)baseUrl
                         keyID:(NSString *)keyid
                     completed:(void (^)(id))comp
{
    if(comp)dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSString *hashName = [self getFileNameWithPort:port BaseUrl:baseUrl KeyId:keyid];
        NSString *documentsDirectory = [self enterTheFilePath];
        NSString *finalFileName = [documentsDirectory stringByAppendingPathComponent:hashName];
        
        //解密并得到responseData
        if ([[NSFileManager defaultManager] fileExistsAtPath:finalFileName]) {
            id model = [NSKeyedUnarchiver unarchiveObjectWithFile:finalFileName];
            comp(model);
        }
    });
}

#pragma mark -Base Method For NSData

- (void)addNetCacheDataWithPort:(NSString *)port
                        baseUrl:(NSString *)baseUrl
                          keyID:(NSString *)keyid
                andResponseData:(NSData *)responseData
{
    NSString *hashName = [self getFileNameWithPort:port BaseUrl:baseUrl KeyId:keyid];
    NSString *documentsDirectory = [self enterTheFilePath];
    NSString *finalFileName = [documentsDirectory stringByAppendingPathComponent:hashName];
    
    //加密并且缓存responseData
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        NSData *forCacheData = [responseData AES256EncryptWithKey:hashName];//加密
        if (responseData.cacheDate) {
            forCacheData.cacheDate = responseData.cacheDate;
        }else {
            forCacheData.cacheDate = [NSDate date];
        }
        Cacheinfo *dat = [[Cacheinfo alloc] init];
        dat.saveData = forCacheData;
        dat.saveTime = forCacheData.cacheDate;
        
        [NSKeyedArchiver archiveRootObject:dat toFile:finalFileName];
    });
   // [forCacheData writeToFile:finalFileName atomically:YES];
}

- (void)getNetCaCheDataWithPort:(NSString *)port
                            baseUrl:(NSString *)baseUrl
                              keyID:(NSString *)keyid
                          completed:(void (^)(NSData *))comp
{
    if(comp)dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSString *hashName = [self getFileNameWithPort:port BaseUrl:baseUrl KeyId:keyid];
        NSString *documentsDirectory = [self enterTheFilePath];
        NSString *finalFileName = [documentsDirectory stringByAppendingPathComponent:hashName];
        
        //解密并得到responseData
        Cacheinfo *dat = nil;
        @try {
            if ([[NSFileManager defaultManager] fileExistsAtPath:finalFileName]) {
                dat = [NSKeyedUnarchiver unarchiveObjectWithFile:finalFileName];
            }
        } @catch (NSException *exception) {
            
        } @finally {
            
        };
        NSData *cahceData = dat.saveData;
        //NSData *cahceData = [NSData dataWithContentsOfFile:finalFileName];
        NSData *responseData = [cahceData AES256DecryptWithKey:hashName];
        responseData.cacheDate = dat.saveTime;
        comp(responseData);
    });
}

- (void)cleanNetCacheDataWithPort:(NSString *)port
                          baseUrl:(NSString*)baseUrl
                            keyID:(NSString *)keyid
                        completed:(void (^)(BOOL))comp
{
    if(comp)dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSString *hashName = [self getFileNameWithPort:port BaseUrl:baseUrl KeyId:keyid];
        NSString *documentsDirectory = [self enterTheFilePath];
        NSString *finalFileName = [documentsDirectory stringByAppendingPathComponent:hashName];
        
        NSError *error = nil;
        BOOL ret = [[NSFileManager defaultManager] removeItemAtPath:finalFileName error:&error];
        comp(ret);
    });
}


- (void)cleanAllNetCache_completed:(void (^)(BOOL))comp {
    if(comp)dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSString *documentsDirectory = [self enterTheFilePath];
        NSError *error = nil;
        BOOL ret = [[NSFileManager defaultManager] removeItemAtPath:documentsDirectory error:&error];
        [self keepCachPath:documentsDirectory];
        comp(ret);
    });
}

@end
